import serial
import websocket
import roslibpy
import threading
import json

class Device:

    def __init__(self, framework):
        self._framework = framework
        self.device_address = ""
        self.device_port = 0
        self.device_state = False
        self.device_connect = False
        self.device_type = ""
        self.device_task = False

    # 连接设备
    def connect_device(self, connect_type, address, port):
        self.device_type = connect_type
        # 如果为串口设备
        if self.device_type == "serial":
            self.device_connect = serial.Serial()
            self.device_connect.port = address
            self.device_connect.baudrate = port
            self.device_connect.bytesize = 8
            self.device_connect.stopbits = serial.STOPBITS_ONE
            self.device_connect.parity = serial.PARITY_NONE
            self.device_connect.timeout = 0.02
            self.device_connect.write_timeout = 0.02
            try:
                self.device_connect.open()
                self.device_task = threading.Thread(name="device_task_work", target=self.device_task_work)
                self.device_task.daemon = True
                self.device_task.start()
                self.device_state = True
            except Exception as e:
                self.device_state = False
        # 如果为网络设备
        if self.device_type == "net":
            self.device_address = address
            self.device_port = port
            self.device_task = threading.Thread(name="device_task_work", target=self.device_task_work)
            self.device_task.daemon = True
            self.device_task.start()
            self.device_state = True
        # 如果为ROS设备
        if self.device_type == "ros":
            self.device_address = address
            self.device_port = port
            self.device_connect = roslibpy.Ros(host=self.device_address, port=self.device_port)
            self.device_connect.run()
            self.device_state = True
    
    # 设备数据读取任务
    def device_task_work(self):
        while True:
            if self.device_state:
                # 如果为串口设备
                if self.device_type == "serial":
                    try:
                        if self.device_state:
                            read_data = b""
                            read_data = self.device_connect.readall()
                            read_data = read_data.decode('utf-8')
                            read_data_json = json.loads(read_data)
                            if read_data_json["type"] and read_data_json["type"] != "":
                                # 将消息发送到消息服务
                                device_data = {"command": "device:message", "body": read_data_json}
                                self._framework.utils.service.write(device_data)
                                # 将串口消息回调至board->message_callback函数
                                if self._framework.board:
                                    self._framework.board.message_callback(read_data_json)
                                # 将串口消息回调至robot->message_callback函数
                                if self._framework.robot:
                                    self._framework.robot.message_callback(read_data_json)
                    except ValueError:
                        continue
                # 如果为网络设备
                if self.device_type == "net":
                    websocket.enableTrace(False)
                    self.device_connect = websocket.WebSocketApp("ws://" + self.device_address + ":" + str(self.device_port), on_message=self.net_device_message, on_error=self.net_device_error, on_close=self.net_device_close)
                    self.device_connect.on_open = self.net_device_open
                    self.device_connect.run_forever()
    
    # 数据写入
    def device_write(self, data):
        if self.device_state:
            # 如果为串口设备
            if self.device_type == "serial":
                self.device_connect.write(json.dumps(data).encode('utf-8'))
            # 如果为网络设备
            if self.device_type == "net":
                self.device_connect.send(json.dumps(data))
    
    # 来自网络设备消息
    def net_device_message(self, ws, message):
        message_json = json.loads(message)
        if message_json["type"] and message_json["type"] != "":
            # 将消息发送到消息服务
            device_data = {"command": "device:message", "body": message_json}
            self._framework.utils.service.write(device_data)
            # 将串口消息回调至board->message_callback函数
            if self._framework.board:
                self._framework.board.message_callback(message_json)
            # 将串口消息回调至robot->message_callback函数
            if self._framework.robot:
                self._framework.robot.message_callback(message_json)
    
    # 打开网络设备
    def net_device_open(self, ws):
        self.device_state = True

    # 网络设备连接出错
    def net_device_error(self, ws, error):
        self.device_state = False

    # 网络设备连接关闭
    def net_device_close(self, ws):
        self.device_state = False

    # 关闭串口
    def serial_device_close(self):
        if self.device_state:
            self.device_connect.close()
            self.device_state = False
